package com.kaguya.vams.config;

import com.kaguya.vams.security.UserDetailsServiceImpl;
import com.kaguya.vams.security.filter.CaptchaFilter;
import com.kaguya.vams.security.filter.JwtAuthenticationFilter;
import com.kaguya.vams.security.handler.JwtAccessDeniedHandler;
import com.kaguya.vams.security.handler.JwtAuthenticationEntryPoint;
import com.kaguya.vams.security.handler.LoginFailureHandler;
import com.kaguya.vams.security.handler.LoginSuccessHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;

/**
 * Security 配置
 *
 * @author : kaguya
 * @date : 20:58 2021/7/29
 */
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    LoginSuccessHandler loginSuccessHandler; //登录成功处理器

    @Autowired
    LoginFailureHandler loginFailureHandler; //登录失败处理器

    @Autowired
    CaptchaFilter captchaFilter; //验证码拦截器

    @Autowired
    UserDetailsServiceImpl userDetailsService; //自定义登录逻辑

    @Autowired
    LogoutSuccessHandler logoutSuccessHandler; //登出成功处理器

    @Autowired
    JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint; //jwt认证失败入口点

    @Autowired
    JwtAccessDeniedHandler jwtAccessDeniedHandler; //权限不足处理器

    //jwt验证过滤器
    @Bean
    JwtAuthenticationFilter jwtAuthenticationFilter() throws Exception {

        return new JwtAuthenticationFilter(authenticationManager());
    }





    private final static String[] URL_WHITELIST = {
            "/login",
            "/logout",
            "/captcha",
            "/favicon.ico"
    };


    @Override
    protected void configure(HttpSecurity http) throws Exception {


        http

            .cors()

        .and()
            //关闭csrf 因为禁用session
            .csrf().disable()

            //禁用session
            .sessionManagement()
            .sessionCreationPolicy(SessionCreationPolicy.STATELESS)

        .and().
            //登录配置
            formLogin()
            .successHandler(loginSuccessHandler)
            .failureHandler(loginFailureHandler)

        .and()
            //登出配置
            .logout()
            .logoutUrl("/logout")
            //登出成功处理器
            .logoutSuccessHandler(logoutSuccessHandler)
        .and()

            //请求拦截
            .authorizeRequests()
                    //放行白名单
                    .antMatchers(URL_WHITELIST)
                    .permitAll()
                    //其他请求全部需要鉴权
                    .anyRequest()
                    .authenticated()

            .and()
                //异常处理器
                .exceptionHandling()
                .authenticationEntryPoint(jwtAuthenticationEntryPoint)
                .accessDeniedHandler(jwtAccessDeniedHandler)
            .and()
            //jwt验证过滤器
            .addFilter(jwtAuthenticationFilter())
            //访客模式验证过滤器
            //.addFilterAfter(visitorFilter, jwtAuthenticationFilter().getClass())
            //验证码过滤器 在登录验证过滤器前
            .addFilterBefore(captchaFilter, UsernamePasswordAuthenticationFilter.class);
    }

    /**
     * 指定AuthenticationManager使用我们自定义的userDetailsService登录逻辑
     * @param auth
     * @throws Exception
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {

        auth.userDetailsService(userDetailsService);
    }

    /**
     * 强散列 密码加密方式
     * @return
     */
    @Bean
    BCryptPasswordEncoder bCryptPasswordEncoder(){
        return new BCryptPasswordEncoder();
    }
}
